//*************************************************************************************
// File:        SimpleTimer.cs
//*************************************************************************************
// Description: Simple timer class, in seconds.
//*************************************************************************************
// Classes:     SimpleTimer
//*************************************************************************************
// Author:      ManOguaR
//*************************************************************************************

using Xeralabs.Common.Platform;

namespace Xeralabs.Timers
{
    /// <summary>
    /// Simple timer class, in seconds.
    /// </summary>
    public class SimpleTimer
    {
        #region Locals
        protected bool isUsingQPF;
        protected bool isTimerStopped;
        protected long ticksPerSecond;
        protected long stopTime;
        protected long lastElapsedTime;
        protected long baseTime;
        #endregion

        #region Properties
        /// <summary>
        /// Get if timer is running.
        /// </summary>
        public bool Running { get { return !isTimerStopped; } }
        #endregion

        /// <summary>
        /// Constructor.
        /// </summary>
        public SimpleTimer()
        {
            isTimerStopped = true;
            ticksPerSecond = 0;
            stopTime = 0;
            lastElapsedTime = 0;
            baseTime = 0;

#if x64
            isUsingQPF = Win64DllImporter.QueryPerformanceFrequency(ref _ticksPerSecond);
#else
            isUsingQPF = Win32DllImporter.QueryPerformanceFrequency(ref ticksPerSecond);
#endif
        }

        /// <summary>
        /// Resets to 0.
        /// </summary>
        public void Reset()
        {
            if (!isUsingQPF) return;

            long time = 0;

            if (stopTime != 0) time = stopTime;
            else
#if x64
                Win64DllImporter.QueryPerformanceCounter(ref time);
#else
                Win32DllImporter.QueryPerformanceCounter(ref time);
#endif

            baseTime = time;
            lastElapsedTime = time;
            stopTime = 0;
            isTimerStopped = false;
        }
        /// <summary>
        /// Starts timer.
        /// </summary>
        public void Start()
        {
            if (!isUsingQPF) return;

            long time = 0;

            if (stopTime != 0) time = stopTime;
            else
#if x64
                Win64DllImporter.QueryPerformanceCounter(ref time);
#else
                Win32DllImporter.QueryPerformanceCounter(ref time);
#endif


            if (isTimerStopped) baseTime += (time - stopTime);
            stopTime = 0;
            lastElapsedTime = time;
            isTimerStopped = false;
        }
        /// <summary>
        /// Pauses the timer.
        /// </summary>
        public void Stop()
        {
            if (!isUsingQPF)
                return;

            if (!isTimerStopped)
            {
                long time = 0;
                if (stopTime != 0)
                    time = stopTime;
                else
#if x64
                    Win64DllImporter.QueryPerformanceCounter(ref time);
#else
                    Win32DllImporter.QueryPerformanceCounter(ref time);
#endif

                stopTime = time;
                lastElapsedTime = time;
                isTimerStopped = true;
            }
        }

        /// <summary>
        /// Get absolute time since system start.
        /// </summary>
        /// <returns>
        /// Time since system start, in seconds.
        /// </returns>
        public double GetAbsoluteTime()
        {
            if (!isUsingQPF) return -1.0;

            long time = 0;

            if (stopTime != 0) time = stopTime;
            else
#if x64
                Win64DllImporter.QueryPerformanceCounter(ref time);
#else
                Win32DllImporter.QueryPerformanceCounter(ref time);
#endif

            double absolueTime = time / (double)ticksPerSecond;
            return absolueTime;
        }
        /// <summary>
        /// Gets time.
        /// </summary>
        /// <returns>
        /// Actual time, in seconds.
        /// </returns>
        public double GetTime()
        {
            if (!isUsingQPF) return -1.0;

            long time = 0;
            if (stopTime != 0) time = stopTime;
            else
#if x64
                Win64DllImporter.QueryPerformanceCounter(ref time);
#else
                Win32DllImporter.QueryPerformanceCounter(ref time);
#endif

            double appTime = (double)(time - baseTime) / (double)ticksPerSecond;
            return appTime;
        }
        /// <summary>
        /// Gets elapsed time between two <see cref="GetElapsedTime"/> calls.
        /// </summary>
        /// <returns>
        /// Time elapsed since the last <see cref="GetElapsedTime"/> call, in seconds.
        /// </returns>
        public double GetElapsedTime()
        {
            if (!isUsingQPF) return -1.0;

            long time = 0;
            if (stopTime != 0) time = stopTime;
            else
#if x64
                Win64DllImporter.QueryPerformanceCounter(ref time);
#else
                Win32DllImporter.QueryPerformanceCounter(ref time);
#endif
            double elapsedTime = (double)(time - lastElapsedTime) / (double)ticksPerSecond;
            lastElapsedTime = time;

            return elapsedTime;
        }
    }
}
